package ldh.im.fxgui.component.message;

import com.jfoenix.controls.JFXDialog;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Cursor;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.scene.text.TextFlow;
import javafx.stage.Popup;
import ldh.im.dto.enums.MessageType;
import ldh.im.fxbase.data.pojo.ImGroup;
import ldh.im.fxbase.data.pojo.ImGroupUser;
import ldh.im.fxbase.data.pojo.ImUser;
import ldh.im.fxbase.data.pojo.ImMessage;
import ldh.im.fxbase.data.pojo.status.ImMessageStatus;
import ldh.im.fxbase.util.*;
import ldh.im.fxgui.component.message.bo.WrapImMessage;
import ldh.im.fxgui.component.message.bo.WrapImMessageStatus;
import ldh.im.fxgui.controller.sub.MessageReadInfoController;
import ldh.im.fxgui.controller.sub.UserHeaderIconController;
import ldh.im.fxgui.handle.IMessageEditorHandler;
import ldh.im.fxgui.pane.MessagePane;
import ldh.im.fxgui.pane.MessagePaneEnum;
import ldh.im.fxgui.service.DefaultFileProgressListener;
import ldh.im.fxgui.service.MessageSendService;
import ldh.im.fxgui.util.UiUtil;
import ldh.im.fxgui.util.UserHeadImageUtil;
import ldh.im.util.DateUtil;
import org.controlsfx.control.PopOver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.List;

/**
 * 用户消息展示模块
 */
public class MessageView extends GridPane implements MessageHandler, IMessageEditorHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(MessageView.class);

    private static final String RECEIVE_BACKGROUND_COLOR = "#ffffff";         // 接收端背景颜色
    private static final String RECEIVE_BACKGROUND_ENTER_COLOR = "#dcdcdc";   // 接收端选中背景颜色
    private static final String RECEIVE_PATH_COLOR = "#ffffff";

    private static final String SENDER_BACKGROUND_COLOR = "#95EC69";          // 发送端背景颜色
    private static final String SENDER_BACKGROUND_ENTER_COLOR = "#7fff00";    // 发送端选中背景颜色
    private static final String SENDER_PATH_COLOR = "#95EC69";

    private ImageView userHeadImageView = new ImageView();
    private TextFlow userNameLabel = new TextFlow();
    private Group contentPane = new Group();
    private Node contentNode = null;
    private Path sendPath = new Path();
    private Path receivePath = new Path();
    private Region hRegion = new Region();
    private RadioButton selectRadio = new RadioButton();      // 多选时使用

    private Label statusLabel = new Label("");           // 消息的动作：发送失败，未读
    private ProgressIndicator progressIndicator = new ProgressIndicator(); // 文件上传和下载进度条

    private WrapImMessage wrapImMessage;
    private MessageListViewHandler messageListViewHandler;
    private StackPane refContainer;
    private Node refPane;
    private StackPane statusPane = new StackPane();

    private Popup popup = new Popup();
    private PopOver popOver = new PopOver();      //未读消息，引用消息
    private BooleanProperty selectProperty = new SimpleBooleanProperty(false);
    private MessagePane messagePane = null;

    public MessageView(MessageListViewHandler messageListViewHandler, WrapImMessage wrapImMessage) {
        this.getStyleClass().add("message-view");
        updateUi(messageListViewHandler, wrapImMessage);
    }

    public void updateUi(MessageListViewHandler messageListViewHandler, WrapImMessage wrapImMessage) {
        this.messageListViewHandler = messageListViewHandler;
        this.wrapImMessage = wrapImMessage;

        selectProperty.bindBidirectional(messageListViewHandler.messageSelectProperty());
        Boolean isReceiveMessage = !wrapImMessage.getImMessage().isSender(UiUtil.getLoginImUser().getUserId());
        contentNode = createNode(wrapImMessage, isReceiveMessage);
        if (contentNode instanceof Pane) {
            ((Pane) contentNode).setMaxWidth(ParamUtil.MESSAGE_WIDTH);
        }
        contentPane.getChildren().add(contentNode);
        this.setGridLinesVisible(true);

        statusPane.getChildren().addAll(statusLabel, progressIndicator);
        if (isReceiveMessage) {
            StackPane.setAlignment(statusLabel, Pos.BOTTOM_LEFT);
        } else {
            StackPane.setAlignment(statusLabel, Pos.BOTTOM_RIGHT);
        }

        statusPane.setMaxSize(40, 40);
        progressIndicator.setMaxSize(30, 30);
        progressIndicator.setPrefSize(30, 30);
        statusLabel.getStyleClass().add("status");
        statusLabel.setText(wrapImMessage.getStatusProperty().getDesc());
        progressIndicator.setVisible(false);

        if (!messageSelectProperty().getValue()) {
            selectRadio.setManaged(false);
            selectRadio.setVisible(false);
        }

        if (wrapImMessage.selectPropertyProperty().getValue()) {
            this.getStyleClass().add("message-selected");
        }

        this.setMouseTransparent(false);
        userHeadImageView.setFitHeight(50);
        userHeadImageView.setFitWidth(50);
        Circle circle = new Circle(25,25,25);
        userHeadImageView.setClip(circle);

        userNameLabel.getStyleClass().add("name-label");

        initUi();
        initPath();
        initEvent();

        setData(wrapImMessage.getImMessage());

        popup.setAutoHide(true);

        initStatusLabelGraphic();
    }

    public void dispose() {
        this.selectProperty.unbindBidirectional(this.messageListViewHandler.messageSelectProperty());
        this.messageListViewHandler = null;
        this.contentNode = null;
        this.wrapImMessage = null;
        this.getChildren().clear();
        this.selectProperty = null;
        messagePane.dispose();
    }

    public void reset() {
        if (messagePane != null) {
            messagePane.reset();
        }
    }

    public void update() {
        if (messagePane != null) {
            messagePane.update();
        }
    }

    private void setData(ImMessage message) {
        if (message.getStatus().isWithdraw()) {
            String userId = UiUtil.getLoginImUser().getUserId();
            if (message.isSender(userId)) {
                Text text = new Text("您撤回了一条消息");
                Text redoText = new Text("重新编辑");
                text.getStyleClass().add("tip");
                redoText.getStyleClass().add("redo-text");
                userNameLabel.getChildren().addAll(text, new Text("  "), redoText);
                redoText.setOnMouseClicked(e->{
                    MessageView.this.setEditorText(message.getContent());
                });
            } else {
                String sendUserId = wrapImMessage.getImMessage().getFromUserId();
                ImUser sendUser = ImCacheFactory.getInstance().getUser(sendUserId);
                Text text = new Text(String.format("$s撤回了一条消息", sendUser.getUserName()));
                text.getStyleClass().add("tip");
                userNameLabel.getChildren().addAll(text);
            }

            return;
        }

        String userName = null;
        if (message.isGroup()) {
            String userId = message.getFromUserId();
            ImGroup imGroup = ImCacheFactory.getInstance().getImGroup(message.getCurrentUserId(), message.getGroupCode());
            ImGroupUser groupUser = imGroup.getGroupUserSet().stream().filter(gu->gu.getUserId().equals(userId)).findFirst().get();
            userName = groupUser.getUserName();
        }

        ImUser imUser = ImCacheFactory.getInstance().getUser(message.getFromUserId());
        if (userName == null) {
            userName = imUser.getUserName();
        }

        Text text = new Text(userName);
        Text region = new Text("  ");
        String serverId = message.getServerId() != null ? message.getServerId() : "";
        Text dateText = new Text();
        dateText.setWrappingWidth(80);
        if (message.isSender(UiUtil.getLoginImUser().getUserId())) {
            if (message.getServerReceiveTime() != null) {
                dateText.setText(DateUtil.format(message.getServerReceiveTime(), "yyyy-MM-dd HH:mm:ss"));
            } else {
                dateText.setText(DateUtil.format(message.getCreateDateTime(),"yyyy-MM-dd HH:mm:ss"));
            }
        } else {
            dateText.setText(DateUtil.format(message.getServerReceiveTime(), "yyyy-MM-dd HH:mm:ss"));
        }
//        dateText.setFont(Font.font(9));
        dateText.getStyleClass().add("text-date");
        userNameLabel.getChildren().clear();
        if (message.getFromUserId().equals(UiUtil.getLoginImUser().getUserId())) { // 发消息
            userNameLabel.getChildren().addAll(dateText, region, text);
        } else {
            userNameLabel.getChildren().addAll(text, region, dateText);
        }

        if (StringUtil.isNotBlank(imUser.getHeadImg())) {
            Image image = UserHeadImageUtil.getHeadImage(imUser.getHeadImg());
            userHeadImageView.setImage(image);
        } else {
            Image image = UserHeadImageUtil.getHeadImage(null);
            userHeadImageView.setImage(image);
        }

        if (message.getMessageType() == MessageType.Image || message.getMessageType() == MessageType.Video) {
            sendPath.setVisible(false);
            receivePath.setVisible(false);
        }
    }

    private Node createNode(WrapImMessage message, boolean isReceiveMessage) {
        MessagePaneEnum messagePaneEnum = MessagePaneEnum.getByMessageType(message.getImMessage().getMessageType());
        this.messagePane = messagePaneEnum.getMessagePane();
        return messagePane.createViewPane(this, message.getImMessage(), isReceiveMessage);
    }

    private void initUi() {
        this.getChildren().clear();
        ImMessage message = wrapImMessage.getImMessage();
        String userId = UiUtil.getLoginImUser().getUserId();
        if (!wrapImMessage.getImMessage().isSender(userId)) { // 接受消息
            if (wrapImMessage.getImMessage().getStatus().isWithdraw()) {
                this.getChildren().add(userNameLabel);
                userNameLabel.setTextAlignment(TextAlignment.CENTER);
                GridPane.setConstraints(userNameLabel, 0, 0, 1, 1, HPos.CENTER, VPos.CENTER);
                GridPane.setHgrow(userNameLabel, Priority.ALWAYS);
            } else {
                this.getChildren().setAll(selectRadio, userHeadImageView, userNameLabel, receivePath, contentPane, statusPane);

                GridPane.setConstraints(selectRadio, 0, 0, 1, 2, HPos.CENTER, VPos.CENTER);
                GridPane.setConstraints(userHeadImageView, 1, 0, 1, 2);
                GridPane.setConstraints(receivePath, 2, 1, 1, 1, HPos.CENTER, VPos.TOP);
                GridPane.setConstraints(userNameLabel, 3, 0, 2, 1, HPos.LEFT, VPos.CENTER);
                GridPane.setConstraints(contentPane, 3, 1, 1, 1, HPos.LEFT, VPos.TOP);
                GridPane.setConstraints(statusPane, 4, 1, 1, 1, HPos.LEFT, VPos.BOTTOM);

                if(message.isRef() && message.getRefMessages() != null && message.getMessageType() != MessageType.Chat) {
                    ImMessage refMessage = message.getRefMessages().get(0);
                    refPane = MessagePaneEnum.getByMessageType(refMessage.getMessageType()).getMessagePane().createRefPane(refMessage, true);
                    refContainer = new StackPane(refPane);
                    refContainer.setMaxWidth(ParamUtil.MESSAGE_WIDTH);
                    refContainer.getStyleClass().add("ref-container");
                    Group group = new Group(refContainer);
                    GridPane.setConstraints(group, 3, 2, 2, 1, HPos.LEFT, VPos.TOP);
                    this.getChildren().add(group);
                }

                ColumnConstraints c1 = new ColumnConstraints();
                c1.setMaxWidth(30);
                ColumnConstraints c2 = new ColumnConstraints(50);
                c2.setHalignment(HPos.CENTER);
                ColumnConstraints c3 = new ColumnConstraints(5);
                ColumnConstraints c4 = new ColumnConstraints();
                c4.setMinWidth(10);
                ColumnConstraints c5 = new ColumnConstraints();
                c5.setHgrow(Priority.ALWAYS);

                RowConstraints r1 = new RowConstraints();
                r1.setValignment(VPos.TOP);
                RowConstraints r2 = new RowConstraints();

                this.getColumnConstraints().addAll(c1, c2, c3, c4, c5);
                this.getRowConstraints().addAll(r1, r2);

//                if (message.isRef() && message.getMessageType() != MessageType.Chat) {
//                    RowConstraints r3 = new RowConstraints();
//                    r3.setMaxHeight(60);
//                    this.getRowConstraints().add(r3);
//                }

                contentNode.setStyle("-fx-background-color: " + RECEIVE_BACKGROUND_COLOR);

                receivePath.setFill(Color.web(RECEIVE_PATH_COLOR));
            }
        } else { // 发消息
            if (message.getStatus().isWithdraw()) { // 消息被撤回
                userNameLabel.setTextAlignment(TextAlignment.CENTER);
                this.getChildren().add(userNameLabel);
                GridPane.setConstraints(userNameLabel, 0, 0, 1, 1, HPos.CENTER, VPos.CENTER);
                GridPane.setHgrow(userNameLabel, Priority.ALWAYS);
            } else {
                GridPane.setConstraints(selectRadio, 0, 0, 1, 2, HPos.CENTER, VPos.CENTER);
                GridPane.setConstraints(hRegion, 1, 0, 1, 2, HPos.LEFT, VPos.TOP);
                GridPane.setConstraints(userNameLabel, 2, 0, 2, 1, HPos.RIGHT, VPos.CENTER);
                GridPane.setConstraints(statusPane, 2, 1, 1, 1, HPos.RIGHT, VPos.BOTTOM);
                GridPane.setConstraints(contentPane, 3, 1, 1, 1, HPos.RIGHT, VPos.CENTER);
                GridPane.setConstraints(sendPath, 4, 1, 1, 1, HPos.CENTER, VPos.TOP);
                GridPane.setConstraints(userHeadImageView, 5, 0, 1, 2, HPos.LEFT, VPos.TOP);

                if(message.isRef() && message.getRefMessages() != null && message.getMessageType() != MessageType.Chat) {
                    ImMessage refMessage = message.getRefMessages().get(0);
                    refPane = MessagePaneEnum.getByMessageType(refMessage.getMessageType()).getMessagePane().createRefPane(refMessage, false);
                    refContainer = new StackPane(refPane);
                    refContainer.setMaxWidth(ParamUtil.MESSAGE_WIDTH);
                    refContainer.getStyleClass().add("ref-container");
                    Group group = new Group(refContainer);
                    GridPane.setConstraints(group, 2, 2, 2, 1, HPos.RIGHT, VPos.TOP);
                    this.getChildren().add(group);
                }

                ColumnConstraints c1 = new ColumnConstraints();
                c1.setMaxWidth(30);
                ColumnConstraints c2 = new ColumnConstraints();
                c2.setHgrow(Priority.ALWAYS);
                ColumnConstraints c3 = new ColumnConstraints();
                c3.setHgrow(Priority.ALWAYS);
                ColumnConstraints c4 = new ColumnConstraints();
                c4.setMinWidth(10);
                ColumnConstraints c5 = new ColumnConstraints(5);
                ColumnConstraints c6 = new ColumnConstraints(50);

                RowConstraints r1 = new RowConstraints();
                r1.setValignment(VPos.TOP);
                RowConstraints r2 = new RowConstraints();

                userNameLabel.setTextAlignment(TextAlignment.RIGHT);
                this.getChildren().setAll(selectRadio, statusPane, userHeadImageView, userNameLabel, contentPane, sendPath);
                this.getColumnConstraints().addAll(c1, c2, c3, c4, c5, c6);
                this.getRowConstraints().addAll(r1, r2);

//                if (message.isRef() && message.getMessageType() != MessageType.Chat) {
//                    RowConstraints r3 = new RowConstraints();
//                    r3.setMaxHeight(60);
//                    this.getRowConstraints().add(r3);
//                }

                contentNode.setStyle("-fx-background-color: " + SENDER_BACKGROUND_COLOR);

                sendPath.setFill(Color.web(SENDER_BACKGROUND_COLOR));
            }
        }
    }

    private void initPath() {
        receivePath.getElements().add(new MoveTo(10, 0));
        receivePath.getElements().add(new LineTo(0, 9));
        receivePath.getElements().add(new LineTo(10, 18));
        receivePath.setStroke(Color.web(RECEIVE_PATH_COLOR));
        receivePath.setStrokeWidth(0.5);
        receivePath.setTranslateY(5);
        receivePath.setTranslateX(0);
//        receivePath.setVisible(false);

        sendPath.getElements().add(new MoveTo(0, 0));
        sendPath.getElements().add(new LineTo(10, 9));
        sendPath.getElements().add(new LineTo(0, 18));
        sendPath.setStroke(Color.web(SENDER_PATH_COLOR));
        sendPath.setStrokeWidth(0.5);
        sendPath.setTranslateY(5);
        sendPath.setTranslateX(0);
//        sendPath.setVisible(false);
    }

    private void initEvent() {
        String userId = UiUtil.getLoginImUser().getUserId();
        contentPane.setOnMouseEntered(e->{
            if (!wrapImMessage.getImMessage().isSender(userId)) {
                contentNode.setStyle("-fx-background-color: " + RECEIVE_BACKGROUND_ENTER_COLOR);
                receivePath.setFill(Color.web(RECEIVE_BACKGROUND_ENTER_COLOR));
            } else {
                contentNode.setStyle("-fx-background-color: " + SENDER_BACKGROUND_ENTER_COLOR);
                sendPath.setFill(Color.web(SENDER_BACKGROUND_ENTER_COLOR));
            }
        });
        contentPane.setOnMouseExited(e->{
            if (!wrapImMessage.getImMessage().isSender(userId)) {
                contentNode.setStyle("-fx-background-color: " + RECEIVE_BACKGROUND_COLOR);
                receivePath.setFill(Color.web(RECEIVE_BACKGROUND_COLOR));
            } else { // 接受端
                contentNode.setStyle("-fx-background-color: " + SENDER_BACKGROUND_COLOR);
                sendPath.setFill(Color.web(SENDER_BACKGROUND_COLOR));
            }
        });

        selectRadio.selectedProperty().bindBidirectional(wrapImMessage.selectPropertyProperty());

        selectRadio.selectedProperty().addListener(l->{
            if (selectRadio.isSelected()) {
                this.getStyleClass().add("message-selected");
            } else {
                this.getStyleClass().remove("message-selected");
            }
        });

        this.setOnMouseClicked(e->{
            if (selectRadio.isVisible()) {
                selectRadio.setSelected(!selectRadio.isSelected());
            }
        });

        messageSelectProperty().addListener(l->{
            if (messageSelectProperty().getValue()) {
                selectRadio.setVisible(true);
                selectRadio.setManaged(true);
                selectRadio.setPrefWidth(30);

            } else {
                selectRadio.setVisible(false);
                selectRadio.setManaged(false);
                this.getStyleClass().remove("message-selected");
            }
        });

        userHeadImageView.setOnMousePressed(e->{
            createUserInfoPopPane(userNameLabel);
        });


        wrapImMessage.statusPropertyProperty().addListener(l->{
            if (wrapImMessage.getStatusProperty() == null) {
                statusLabel.setText("");
                return;
            }
            statusLabel.setText(wrapImMessage.getStatusProperty().getDesc());
            initStatusLabelGraphic();
            if (this.wrapImMessage.getImMessage().getMessageType().isFile()) {
                rebuildContent();
            }
        });
        wrapImMessage.isProgressProperty().addListener(l->{
            LOGGER.info("messageId:{}, wrapMessage.isProgress changed: {}", wrapImMessage.getImMessage().getServerId(), wrapImMessage.isProgress());
            if (wrapImMessage.isProgress()) {
                statusLabel.setVisible(false);
                progressIndicator.setVisible(true);
            } else {
                statusLabel.setVisible(true);
                progressIndicator.setVisible(false);
            }
        });
        this.progressIndicator.progressProperty().bind(wrapImMessage.progressProperty());

        // 消息已读弹出框
        if (wrapImMessage.getStatusProperty() == WrapImMessageStatus.no_send) {
            statusLabel.setOnMouseClicked(e->{
                ImMessage message = this.wrapImMessage.getImMessage();
                message.setStatus(ImMessageStatus.sending);
                UiUtil.uiUpdateMessage(message);
                MessageSendService messageSendService = new MessageSendService();
                ThreadPoolUtil.submit(()->{
                    try {
                        messageSendService.sendMessages(Arrays.asList(message));
                    } catch (Exception ee) {
                        message.setStatus(ImMessageStatus.failure);
                        FxThreadUtil.runLater(()->{
                            UiUtil.uiUpdateMessage(message);
                        });
                        LOGGER.error("send message error, messageId: {}, errorMsg {}", message.getId(), ee);
                    }
                });
            });
        } else if (wrapImMessage.getImMessage().isGroup() && wrapImMessage.getImMessage().isSender(userId)) {
            statusLabel.setCursor(Cursor.HAND);
            statusLabel.getStyleClass().add("link");
            statusLabel.setOnMouseClicked(e->{
                String key = "/fxml/sub/MessageReadInfoPane.fxml";
                RegionUtil.FxmlBean<Pane, MessageReadInfoController> fxmlBean = SoftMapUtil.getCache(key);
                if (fxmlBean == null) {
                    fxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource(key));
                }
                fxmlBean.getController().setImMessage(wrapImMessage.getImMessage());
//                fxmlBean.getController().setDialog(null);
//                popOver.setContentNode(fxmlBean.getNode());
//                if (wrapImMessage.getImMessage().isSender(userId)) {
//                    popOver.setArrowLocation(PopOver.ArrowLocation.RIGHT_CENTER);
//                } else {
//                    popOver.setArrowLocation(PopOver.ArrowLocation.LEFT_CENTER);
//                }
//                popOver.show(statusLabel, 10);

                JFXDialog dialog = DialogUtil.show(fxmlBean.getNode(), false);
                dialog.setPrefSize(300, 400);
                fxmlBean.getController().setDialog(dialog);

            });
        } else if (wrapImMessage.getStatusProperty() == WrapImMessageStatus.no_upload) {
            statusLabel.setOnMouseClicked(e->{
                wrapImMessage.statusPropertyProperty().set(WrapImMessageStatus.sending);
                initStatusLabelGraphic();
                try {
                    RpcUtil.getImService().sendFile(wrapImMessage.getImMessage(), new DefaultFileProgressListener());
                } catch (Exception error) {
                    LOGGER.error("send file error", error);
                }
            });
        } else if (wrapImMessage.getStatusProperty() == WrapImMessageStatus.no_download) {
            statusLabel.setOnMouseClicked(e->{
                wrapImMessage.statusPropertyProperty().set(WrapImMessageStatus.downloading);
                initStatusLabelGraphic();
                try {
                    RpcUtil.getImService().downloadFile(wrapImMessage.getImMessage(), new DefaultFileProgressListener(), m-> UiUtil.uiUpdateMessage(m));
                } catch (Exception error) {
                    LOGGER.error("send file error", error);
                }
            });
        }

        wrapImMessage.contentProperty().addListener((l)->{
            rebuildContent();
        });
    }

    private void rebuildContent() {
        Boolean isReceiveMessage = !wrapImMessage.getImMessage().isSender(UiUtil.getLoginImUser().getUserId());
        contentNode = createNode(wrapImMessage, isReceiveMessage);
        if (contentNode instanceof Pane) {
            ((Pane) contentNode).setMaxWidth(ParamUtil.MESSAGE_WIDTH);
        }
        contentPane.getChildren().setAll(Arrays.asList(contentNode));
    }

    private void createUserInfoPopPane(Pane pane) {
        Pane userHeaderIconPane = createUserPane();
        popup.getContent().setAll(userHeaderIconPane);

        String userId = UiUtil.getLoginImUser().getUserId();
        if (wrapImMessage.getImMessage().isSender(userId)) {
            double x = RegionUtil.calcAnchorX(pane, PopupPos.down_east, userHeaderIconPane) + pane.getWidth() + 50;
            double y = RegionUtil.calcAnchorY(pane, PopupPos.down_east, userHeaderIconPane);
            popup.show(userHeadImageView.getScene().getWindow(), x, y);
        } else {
            double x = RegionUtil.calcAnchorX(pane, PopupPos.down_east, userHeaderIconPane);
            double y = RegionUtil.calcAnchorY(pane, PopupPos.down_east, userHeaderIconPane);
            popup.show(userHeadImageView.getScene().getWindow(), x, y);
        }
    }

    private GridPane createUserPane() {
        String key = "/fxml/sub/UserHeaderIconPane.fxml";
        RegionUtil.FxmlBean<GridPane, UserHeaderIconController> fxmlBean = RegionUtil.loadFxmlBean(this.getClass().getResource(key));
        fxmlBean.getController().setImUser(UiUtil.getLoginImUser());
        fxmlBean.getController().setMainController(UiUtil.getMainController());
        return fxmlBean.getNode();
    }

    private void initStatusLabelGraphic() {
        statusLabel.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        statusLabel.setTooltip(new Tooltip(statusLabel.getText()));
        if (wrapImMessage.getStatusProperty() == WrapImMessageStatus.no_send) {
            statusLabel.setGraphic(loadImage("/imgs/no_send.png"));
        } else if (wrapImMessage.getStatusProperty() == WrapImMessageStatus.no_read) {
            statusLabel.setGraphic(loadImage("/imgs/no_read.png"));
        } else if (wrapImMessage.getStatusProperty() == WrapImMessageStatus.no_upload) {
            statusLabel.setGraphic(loadImage("/imgs/no_upload.png"));
        } else if (wrapImMessage.getStatusProperty() == WrapImMessageStatus.no_download) {
            statusLabel.setGraphic(loadImage("/imgs/no_download.png"));
        } else if (wrapImMessage.getStatusProperty() == WrapImMessageStatus.sending) {
            statusLabel.setGraphic(loadImage("/imgs/loading.gif"));
        } else if (wrapImMessage.getStatusProperty() == WrapImMessageStatus.empty) {
            statusLabel.setGraphic(null);
        }
    }

    private ImageView loadImage(String path) {
        Image cacheImage = SoftMapUtil.getWeakCache(path);
        if (cacheImage != null) {
            ImageView imageView = new ImageView(cacheImage);
            imageView.setFitHeight(15);
            imageView.setFitWidth(15);
            return imageView;
        }
        Image image = new Image(this.getClass().getResource(path).toExternalForm(), true);
        SoftMapUtil.weakCache(path, image);
        ImageView imageView = new ImageView(image);
        imageView.setFitHeight(15);
        imageView.setFitWidth(15);
        return imageView;
    }

    @Override
    public void deleteMessage(ImMessage message) {
        this.messageListViewHandler.deleteMessage(message);
    }

    @Override
    public void deleteMessages(List<ImMessage> messages) {
        this.messageListViewHandler.deleteMessages(messages);
    }

    @Override
    public BooleanProperty messageSelectProperty() {
        return selectProperty;
    }

    @Override
    public void refMessage(ImMessage imMessage) {
        messageListViewHandler.refMessage(imMessage);
    }

    @Override
    public StackPane getDialogRoot() {
        return messageListViewHandler.getDialogRoot();
    }

    @Override
    public void setEditorText(String content) {
        messageListViewHandler.getMessageEditorService().setEditorText(content);
    }

    @Override
    public void setRefMessage(ImMessage message) {
        messageListViewHandler.getMessageEditorService().setRefMessage(message);
    }
}
